#include <linux/module.h>
#include <linux/proc_fs.h>
#include <linux/slab.h>
#include <linux/uaccess.h>
#include <linux/usb.h>
#include <linux/kernel.h>

struct class_info {
        int class;
        char *class_name;
};

/*
 * Device and/or Interface Class codes
 * as found in bDeviceClass or bInterfaceClass
 * and defined by www.usb.org documents
#define USB_CLASS_PER_INTERFACE         0       // for DeviceClass 
#define USB_CLASS_AUDIO                 1
#define USB_CLASS_COMM                  2
#define USB_CLASS_HID                   3
#define USB_CLASS_PHYSICAL              5
#define USB_CLASS_STILL_IMAGE           6
#define USB_CLASS_PRINTER               7
#define USB_CLASS_MASS_STORAGE          8
#define USB_CLASS_HUB                   9
#define USB_CLASS_CDC_DATA              0x0a
#define USB_CLASS_CSCID                 0x0b    // chip+ smart card 
#define USB_CLASS_CONTENT_SEC           0x0d    // content security 
#define USB_CLASS_VIDEO                 0x0e
#define USB_CLASS_WIRELESS_CONTROLLER   0xe0
#define USB_CLASS_PERSONAL_HEALTHCARE   0x0f
#define USB_CLASS_AUDIO_VIDEO           0x10
#define USB_CLASS_BILLBOARD             0x11
#define USB_CLASS_USB_TYPE_C_BRIDGE     0x12
#define USB_CLASS_MISC                  0xef
#define USB_CLASS_APP_SPEC              0xfe
#define USB_CLASS_VENDOR_SPEC           0xff

#define USB_SUBCLASS_VENDOR_SPEC        0xff
 */

static const struct class_info clas_info[] = {
        /* max. 5 chars. per name string */
        {USB_CLASS_PER_INTERFACE,       ">ifc"},
        {USB_CLASS_AUDIO,               "audio"},
        {USB_CLASS_COMM,                "comm."},
        {USB_CLASS_HID,                 "HID"},
        {USB_CLASS_PHYSICAL,            "PID"},
        {USB_CLASS_STILL_IMAGE,         "still"},
        {USB_CLASS_PRINTER,             "print"},
        {USB_CLASS_MASS_STORAGE,        "stor."},
        {USB_CLASS_HUB,                 "hub"},
        {USB_CLASS_CDC_DATA,            "data"},
        {USB_CLASS_CSCID,               "scard"},
        {USB_CLASS_CONTENT_SEC,         "c-sec"},
        {USB_CLASS_VIDEO,               "video"},
        {USB_CLASS_WIRELESS_CONTROLLER, "wlcon"},
        {USB_CLASS_MISC,                "misc"},
        {USB_CLASS_APP_SPEC,            "app."},
        {USB_CLASS_VENDOR_SPEC,         "vend."},
        {-1,                            "unk."}         /* leave as last */
};

static const char *class_decode(const int class)
{
        int ix;

        for (ix = 0; clas_info[ix].class != -1; ix++)
                if (clas_info[ix].class == class)
                        break;
        return clas_info[ix].class_name;
}

static int foreach_callback(struct usb_device *udev, void *data){
	struct usb_interface *intf;
	int i;
	printk("product=%s manufacturer=%s serial=%s class=%02x, subclass=%02x prot=%02x vid=%04x pid=%04x\n",
			udev->product?udev->product:"NULL",
			udev->manufacturer?udev->manufacturer:"NULL",
			udev->serial?udev->serial:"NULL",
			udev->descriptor.bDeviceClass,
			udev->descriptor.bDeviceSubClass,
			udev->descriptor.bDeviceProtocol,
			udev->descriptor.idVendor,
			udev->descriptor.idProduct
			);

	for(i = 0; i < udev->actconfig->desc.bNumInterfaces; i++){
		intf = udev->actconfig->interface[i];
		if(intf){
			printk("intf%d class=%02x, subclass=%02x, prot=%02x\n", i,
					intf->cur_altsetting->desc.bInterfaceClass,
					intf->cur_altsetting->desc.bInterfaceSubClass,
					intf->cur_altsetting->desc.bInterfaceProtocol
					);
			if(intf->cur_altsetting->desc.bInterfaceClass == USB_CLASS_MASS_STORAGE){
				printk("driver=%p\n", intf->dev.driver);
				usb_driver_release_interface(to_usb_driver(intf->dev.driver), intf);
				printk("driver=%p\n", intf->dev.driver);

			}
		}


	}

	return 0;
}

static int notify_dev_add_func(struct usb_device *udev){
	int i;
	struct usb_interface *intf;
		printk("product=%s manufacturer=%s serial=%s class=%02x, subclass=%02x prot=%02x vid=%04x pid=%04x\n",
			udev->product?udev->product:"NULL",
			udev->manufacturer?udev->manufacturer:"NULL",
			udev->serial?udev->serial:"NULL",
			udev->descriptor.bDeviceClass,
			udev->descriptor.bDeviceSubClass,
			udev->descriptor.bDeviceProtocol,
			udev->descriptor.idVendor,
			udev->descriptor.idProduct
			);
 
	//device_del(&udev->dev);
	
		/*
	for(i = 0; i < udev->actconfig->desc.bNumInterfaces; i++){
		intf = udev->actconfig->interface[i];
		if(intf){
			printk("intf%d class=%02x, subclass=%02x, prot=%02x\n", i,
					intf->cur_altsetting->desc.bInterfaceClass,
					intf->cur_altsetting->desc.bInterfaceSubClass,
					intf->cur_altsetting->desc.bInterfaceProtocol
					);
			if(intf->cur_altsetting->desc.bInterfaceClass == USB_CLASS_MASS_STORAGE){
				printk("driver=%p\n", intf->dev.driver);
				usb_driver_release_interface(to_usb_driver(intf->dev.driver), intf);
				printk("driver=%p\n", intf->dev.driver);

			}
		}


	}
	*/



	return 0;
}

static int usb_notify(struct notifier_block *self, unsigned long action, void *dev){
	//printk("%lu\n", action);
	switch(action){
		case USB_DEVICE_ADD:
			notify_dev_add_func(dev);
			break;
		case USB_DEVICE_REMOVE:
			break;
	}
	return NOTIFY_OK;
}

static struct notifier_block usb_notify_block = {
	.notifier_call = usb_notify,
};

static int usb_foreach(void){
	//usb_for_each_dev(NULL, foreach_callback);
	
	usb_register_notify(&usb_notify_block);
	

	return 0;
}



static int __init proc_init(void){
	usb_foreach();
	return 0;
}

//模块退出函数
static void __exit proc_exit(void){
	usb_unregister_notify(&usb_notify_block);
}

module_init(proc_init);
module_exit(proc_exit);
MODULE_AUTHOR("NFS");
MODULE_LICENSE("GPL");
